﻿using System;
using System.Threading;
using System.Collections.Generic;

using SBPweb.Forge.Contracts.Events;
using SBPweb.Forge.Contracts.Components;

using SBPweb.Communication.Shared.Library.Contacts;

namespace SBPweb.Communication.Shared.Library.Connections
{

    public abstract class ConnectionManagerBase : InitializableBase, IConnectionManager
    {

        #region Protected fields

        protected MessengerBase messenger;

        #endregion

        #region Constructor logic

        protected ConnectionManagerBase(MessengerBase messenger)
        {
            this.messenger = messenger;
        }

        #endregion

        #region Property accessors

        protected IMessenger Messenger
        {
            get
            {
                return messenger;
            }
        }

        public bool IsConnected
        {
            get;
            protected set;
        }

        public IConnectionManagerConfiguration Configuration
        {
            get;
            protected set;
        }

        public virtual string UserName
        {
            get;
            protected set;
        }

        public virtual string Resource
        {
            get;
            set;
        }

        #endregion

        #region Events

        public event EventHandler Connecting;

        public event EventHandler Connected;

        public event EventHandler<CancelEventArgs> Disconnecting;

        public event EventHandler Disconnected;

        public event EventHandler<ContactPresenceStateBaseCancelEventArgs> PresenceStateChanging;

        public event EventHandler<ContactPresenceStateBaseEventArgs> PresenceStateChanged;

        #endregion

        #region Methods

        #region Configuration

        public void ApplyConfiguration(IConnectionManagerConfiguration configuration)
        {
            Configuration = configuration;
        }

        #endregion

        #region Connectivity

        public abstract void Connect(string userName, string password);

        public abstract void Disconnect();

        protected void OnConnecting(object sender, EventArgs e)
        {
            if (Connecting != null)
            {
                Connecting(sender, e);
            }
        }

        protected void OnConnected(object sender, EventArgs e)
        {
            if (Connected != null)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
                {
                    Connected.DynamicInvoke(sender, e);
                }), null);
            }
        }

        protected void OnDisconnecting(object sender, CancelEventArgs e)
        {
            if (Disconnecting != null)
            {
                Disconnecting(sender, e);
            }
        }

        protected void OnDisconnected(object sender, EventArgs e)
        {
            if (Disconnected != null)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
                {
                    Disconnected.DynamicInvoke(sender, e);
                }), null);
            }
        }

        #endregion

        #region State management

        public abstract List<ContactPresenceStateBase> EnumeratePresenceStates();

        public void SetPresenceState(ContactPresenceStateBase state)
        {
            ContactPresenceStateBaseCancelEventArgs psce = new ContactPresenceStateBaseCancelEventArgs(null, state);
            OnPresenceStateChanging(this, psce);
            if (psce.Cancel)
            {
                return;
            }
            OnSetPresenceState(this, psce);
            OnPresenceStateChanged(this, psce);
        }

        protected abstract void OnSetPresenceState(object sender, ContactPresenceStateBaseCancelEventArgs e);

        protected void OnPresenceStateChanging(object sender, ContactPresenceStateBaseCancelEventArgs e)
        {
            if (PresenceStateChanging != null && !e.Cancel)
            {
                PresenceStateChanging(this, e);
            }
        }

        protected void OnPresenceStateChanged(object sender, ContactPresenceStateBaseCancelEventArgs e)
        {
            if (PresenceStateChanged != null && !e.Cancel)
            {
                PresenceStateChanged(this, e);
            }
        }

        #endregion

        #endregion

    }

}